using System;
using GraphEditor.Runtime;

namespace GraphEditor.Editor
{
    /// <summary>
    /// 编辑器框架的核心基类：必须实现，用以进行视图和逻辑之间的绑定。
    /// </summary>
    public abstract class BaseGraphEditor
    {
        /// <summary>
        /// 编辑器的视图类
        /// </summary>
        protected GraphView GraphView { get; private set; }
        /// <summary>
        /// 整个图的画布对象
        /// </summary>
        protected GraphCanvas GraphCanvas { get; private set; }

        /// <summary>
        /// 初始化方法，打开窗口的时候调用
        /// </summary>
        /// <param name="graphCanvas"></param>
        /// <param name="graphView"></param>
        internal void Initialize(GraphCanvas graphCanvas)
        {
            GraphCanvas = graphCanvas;

            // 1.初始化逻辑类实例，不存在的话手动创建一个
            GetOrCreateLogicInstance();
            // 2.实现方法GetLogicInstance(string id)，方便后续获取逻辑类实例

            // 1.首先读取视图对象。
            // 视图对象为空，则自动构建一个默认视图对象。
            // 视图对象不为空，则直接使用。
        }
        /// <summary>
        /// 创建逻辑类的对象实例（必须实现，用来创建逻辑类对象实例）
        /// </summary>
        /// <returns></returns>
        public virtual void GetOrCreateLogicInstance()
        {
            string logicType = GraphCanvas.LogicType;
            IElement logicInstance = GraphCanvas.LogicInstance;
            if (logicInstance != null)
            {
                if (logicInstance.GetType().FullName != logicType) throw new ArgumentException("logicType和逻辑类实例类型不一致，无法实例化");
                return;
            }
            if (string.IsNullOrEmpty(logicType)) throw new ArgumentException("logicType为空，无法实例化");
            Type type = Type.GetType(logicType) ?? throw new ArgumentException("logicType不存在，无法实例化");
            if (!typeof(IElement).IsAssignableFrom(type)) throw new ArgumentException("logicType不是IElement的子类，无法实例化");
            GraphCanvas.LogicInstance = Activator.CreateInstance(type) as IElement;
        }
        /// <summary>
        /// 根据Id获取逻辑类的对象实例
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public abstract IElement GetLogicInstance(string id);
        /// <summary>
        /// 判断两个端口是否可以连接（必须实现，用来判断逻辑类上的逻辑节点是否可以连接）
        /// </summary>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <returns></returns>
        public abstract bool CanConnect(PortData from, PortData to);
        /// <summary>
        /// 创建连接（自己处理逻辑类数据）
        /// </summary>
        /// <param name="edge"></param>
        /// <param name="from"></param>
        /// <param name="to"></param>
        public abstract void OnConnected(EdgeData edge, IElement from, IElement to);
        /// <summary>
        /// 删除连接（自己处理逻辑类数据）
        /// </summary>
        /// <param name="edge"></param>
        /// <param name="from"></param>
        /// <param name="to"></param>
        public abstract void OnDisconnected(EdgeData edge, IElement from, IElement to);
        /// <summary>
        /// “烘焙”/“导出”：将编辑器的扁平数据结构，转换成用户自己的运行时逻辑结构。
        /// 这是 Bake() 方法的核心。
        /// </summary>
        /// <returns>用户自己的、可被序列化为runtimeData的根逻辑对象</returns>
        public abstract string Bake();
    }
}